//Random Game Engine
//Copyright (C) 2013  Nikolay Dionisov

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "StateManager.h"
namespace re
{
	namespace core
	{
		void StateListener::Update()
		{
			StateMessagePtr msg;
			while(queue_.try_pop(&msg))
			{
				MessageType type = msg->GetMessageType();
				StateListenerCallbackMap::iterator clb_find = callback_map.find(type);
				if(clb_find == callback_map.end())
				{
					//well.... fail
					ASSERT(0);
				}
				clb_find->second->Call(this, msg);
			}
		}
		void StateListener::HandleMessage(StateMessagePtr msg)
		{
			queue_.push(&msg);
		}
		void StateListener::SetMsgCallback(MessageType type, StateListenerCallbackPtr callback)
		{
			callback_map[type] = callback;
		}
		void StateListener::RemoveMsgCallback(MessageType type)
		{
			callback_map.erase(type);
		}


		MessageType StateManager::GenerateNewMsgType()
		{
			std::unique_lock<std::mutex> lock(mutex_);
			while(1)
			{
				last_messagetype++;
				if(last_messagetype == 0)
				{
					last_messagetype++;
				}
				StateListenerMap::iterator listener_iter = listenermap_.find(last_messagetype);
				if(listener_iter == listenermap_.end())
				{
					return last_messagetype;
				}
			}
			return 0;
		}
		void StateManager::RegisterMsgType(MessageType type)
		{
			std::unique_lock<std::mutex> lock(mutex_);
			StateListenerMap::iterator i = listenermap_.find(type);
			if(i != listenermap_.end())
			{
				ASSERT(0);
			}
			listenermap_[type] = StateListenerList();
		}
		void StateManager::UnregisterMsgType(MessageType type)
		{
			std::unique_lock<std::mutex> lock(mutex_);
			StateListenerMap::iterator i = listenermap_.find(type);
			if(i == listenermap_.end())
			{
				ASSERT(0);
			}
			listenermap_.erase(type);
		}
		void StateManager::RegisterListener(StateListenerPtr listener, MessageType type)
		{
			std::unique_lock<std::mutex> lock(mutex_);
			//check if there is actually such message type.
			StateListenerMap::iterator i = listenermap_.find(type);
			if(i == listenermap_.end())
			{
				ASSERT(0);
			}
			//check if it has already subscribed
			StateListenerList::iterator search_iter = i->second.begin();
			StateListenerList::iterator search_end = i->second.end();
			while(search_iter != search_end)
			{
				if(*search_iter == listener)
				{
					//listener already added...
					ASSERT(0);
				}
				++search_iter;
			}
			//subscribe for it
			i->second.push_back(listener);
		}
		void StateManager::UnregisterListener(StateListenerPtr listener)
		{
			std::unique_lock<std::mutex> lock(mutex_);
			//loop through all events
			StateListenerMap::iterator map_iter = listenermap_.begin();
			StateListenerMap::iterator map_end = listenermap_.end();
			while(map_iter != map_end)
			{
				StateListenerList::iterator search_iter = map_iter->second.begin();
				StateListenerList::iterator search_end = map_iter->second.end();
				while(search_iter != search_end)
				{
					if(*search_iter == listener)
					{
						map_iter->second.erase(search_iter);
					}
					++search_iter;
				}
				++map_iter;
			}

		}

		void StateManager::SendMsg(StateMessagePtr msg)
		{
			std::unique_lock<std::mutex> lock(mutex_);
			MessageType type = msg->GetMessageType();
			StateListenerMap::iterator i = listenermap_.find(type);
			if(i == listenermap_.end())
			{
				//unknown event type
				ASSERT(0);
			}
			StateListenerList::iterator search_iter = i->second.begin();
			StateListenerList::iterator search_end = i->second.end();
			while(search_iter != search_end)
			{
				search_iter->get()->HandleMessage(msg);
				++search_iter;
			}
		}

		StateListenerPtr StateManager::CreateStateListener()
		{
			return StateListenerPtr(new StateListener());
		}
	}
}